package game.graphics.animations;

import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glPopMatrix;
import static org.lwjgl.opengl.GL11.glPushMatrix;
import static org.lwjgl.opengl.GL11.glRotatef;
import static org.lwjgl.opengl.GL11.glTranslatef;
import static org.lwjgl.opengl.GL11.glVertex2i;
import helpers.Circle;

import java.awt.Rectangle;
import java.io.Serializable;

import application.Configuration;
import application.Window;

/**
 * Draws person with animations.
 * 
 * @author Drahomir Karchnak, Tomas Zima
 */
public class Person implements Serializable
{
	/**
	 * Constructor.
	 */
	public Person()
	{
		regenerateBoundingBoxes();
	}

	/**
	 * Redraws person on specified position.
	 * 
	 * @param cameraX
	 * @param cameraY
	 */
	public void redraw(int cameraX, int cameraY)
	{
		// Coordinates for drawing
		int relX = (int) this.positionX - cameraX + (Configuration.WINDOW_WIDTH / 2);
		int relY = (int) this.positionY - cameraY + (Configuration.WINDOW_HEIGHT / 2);
		
		// Save current state
		boolean mix = Window.isTexColorMixingEnabled();
		
		Window.disableTexColorMixing();
		Window.disableTexturing();

		// Back leg
		glPushMatrix();
		glTranslatef(relX + 16, relY - 22, 0);
		glRotatef(angle, 0, 0, 1);
		glTranslatef(-(relX + 16), -(relY - 22), 0);
		glBegin(GL_QUADS);
			glColor3f(0.3f, 0.0f, 0.0f);
			glVertex2i(relX + 10, relY - 22);
			glVertex2i(relX + 22, relY - 22);
			glVertex2i(relX + 22, relY);
			glVertex2i(relX + 10, relY);
		glEnd();
		glPopMatrix();

		// Back arm
		glPushMatrix();
		glTranslatef(relX + 16, relY - 40, 0);
		glRotatef(angle, 0, 0, 1);
		glTranslatef(-(relX + 16), -(relY - 40), 0);
		glBegin(GL_QUADS);
			glColor3f(0.1f, 0.0f, 0.0f);
			glVertex2i(relX + 12, relY - 40);
			glVertex2i(relX + 20, relY - 40);
			glVertex2i(relX + 20, relY - 20);
			glVertex2i(relX + 12, relY - 20);
		glEnd();
		glPopMatrix();
		
		// Body
		glBegin(GL_QUADS);
			glColor3f(0.5f, 0.0f, 0.0f);
			glVertex2i(relX + 5, relY - 44);
			glVertex2i(relX + 27, relY - 44);
			glVertex2i(relX + 27, relY - 22);
			glVertex2i(relX + 5, relY - 22);
		glEnd();
					
		// Front leg
		glPushMatrix();
		glTranslatef(relX + 16, relY - 22, 0);
		glRotatef(-angle, 0, 0, 1);
		glTranslatef(-(relX + 16), -(relY - 22), 0);
		glBegin(GL_QUADS);
			glColor3f(0.3f, 0.0f, 0.0f);
			glVertex2i(relX + 10, relY - 22);
			glVertex2i(relX + 22, relY - 22);
			glVertex2i(relX + 22, relY);
			glVertex2i(relX + 10, relY);
		glEnd();
		glPopMatrix();
		
		float oldAngle = this.angle;
		
		if (isShooting())
		{
			this.angle = 90.0f;
		}
		
		// Front arm
		glPushMatrix();
		glTranslatef(relX + 16, relY - 40, 0);
		glRotatef(-angle, 0, 0, 1);
		glTranslatef(-(relX + 16), -(relY - 40), 0);		
		glBegin(GL_QUADS);
			glColor3f(0.1f, 0.0f, 0.0f);
			glVertex2i(relX + 12, relY - 40);
			glVertex2i(relX + 20, relY - 40);
			glVertex2i(relX + 20, relY - 20);
			glVertex2i(relX + 12, relY - 20);
		glEnd();
		glPopMatrix();
		
		if (isShooting())
		{
			this.angle = oldAngle;
		}

		glColor3f(0.7f, 0.0f, 0.0f);
		Circle.drawFilled(relX + 16, relY - 54, 10, 30);
		
		// Restore previous state
		if (mix)
		{
			Window.enableTexColorMixing();
		}
		
		Window.enableTexturing();
	}
	
	/**
	 * Set person on defined coordinates.
	 * 
	 * @param x
	 * @param y
	 */
	public void setPositionXY(float x, float y)
	{
		this.positionX	= x;
		this.positionY	= y;
		regenerateBoundingBoxes();		
	}
	
	public void setPositionX(float x)
	{
		this.positionX	= x;
		regenerateBoundingBoxes();
	}
	
	public void setPositionY(float y)
	{
		this.positionY	= y;
		regenerateBoundingBoxes();
	}
	
	public float getPositionX()
	{
		return positionX;
	}
	
	public float getPositionY()
	{
		return positionY;
	}
	
	/**
	 * Movement at the X axis (in pixels).
	 * 
	 * If value is positive, then it means movement to right. Negative value 
	 * means movement to left.
	 * 
	 * @param movement
	 */
	public void moveAtXAxis(float movement)
	{
		this.positionX += movement;
		regenerateBoundingBoxes();
		
		/*if (movement > 0)
		{
			if (phase)
			{
				angle += animationAngleChange;
			} 
			else
			{
				angle -= animationAngleChange;
			}
		}
		else
		if (movement < 0)
		{
			if (phase)
			{
				angle -= animationAngleChange;
			}
			else
			{
				angle += animationAngleChange;
			}
		}
		
		if (angle >= 40 || angle <= -40)
		{
			angle	= Math.abs(angle) / angle * -1 * -40;
			phase	= !phase;
		}*/
		

		if (phase)
		{
			angle += (movement / 64.0f) * 80;
		}
		else
		{
			angle -= (movement / 64.0f) * 80;
		}
		
		if (angle > 40)
		{
			phase = !phase;
		}
		else
		if (angle < -40)
		{
			phase = !phase;
		}
	}

	
	/**
	 * Movement at the Y axis (in pixels).
	 * 
	 * If value is positive, then it means movement to down. Negative value 
	 * means movement to up.
	 * 
	 * @param movement
	 */
	public void moveAtYAxis(float movement)
	{
		this.positionY += movement;
		regenerateBoundingBoxes();
	}
	
	/**
	 * Set person to the default position.
	 * It means that person will be drawn equally as when it was created.
	 */
	public void animationDefaultState()
	{
		this.angle = 0;
	}
	
	/**
	 * Returns all bounding boxes.
	 * 
	 * @return
	 */
	public Rectangle[] getBoundingBoxes()
	{
		return boundingBoxes;
	}

	/**
	 * Regenerates all bounding boxes.
	 * This should be called after every movement etc.
	 */
	private void regenerateBoundingBoxes()
	{
		boundingBoxes[0] = new Rectangle((int) positionX + 5, (int) positionY - 62, 22, 62);
	}
	
	/**
	 * Makes person shooting.
	 */
	public void enableShooting()
	{
		this.shooting = true;
	}
	
	/**
	 * Makes person non-shooting.
	 */
	public void disableShooting()
	{
		this.shooting = false;
	}
	
	/**
	 * Checks if person is shooting or not.
	 * 
	 * @return
	 * 	true: shooting
	 * 	false: not shooting
	 */
	public boolean isShooting()
	{
		return this.shooting;
	}
	
	// Position of player
	private float	positionX;
	private float	positionY;
	
	// Definition of current animation frame
	private float	angle		= 0.0f;
	private boolean	phase		= false;
	private boolean shooting	= false;
	
	// Change of rotation angle (legs, arms) when animating
	private final float animationAngleChange = 10.0f;
	
	// Bounding boxes
	private Rectangle boundingBoxes[] = new Rectangle[1];
}
